package com.yanyuan.snio.part;

import lombok.extern.slf4j.Slf4j;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;

/**
 * @author: yanyuan
 * @Date: 2021/2/2 11:51
 * @Description:
 * 一、缓冲区（Buffer）：
 * 在java NIO中负责数据的存取，
 * 缓存区就是数组，用于存储不同数据类型的数据。
 * 根据数据类型不同（boolean除外），提供了相应类型的缓冲区。
 * ByteBuffer
 * CharBuffer
 * ShortBuffer
 * IntBuffer
 * LongBuffer
 * FloatBuffer
 * DoubleBuffer
 * 上述缓冲区的管理方式几乎一致，通过allocate()获取缓冲区
 *
 * 二、缓冲区存储数据的核心方法。
 * put(): 存入数据到缓冲去
 * get(): 获取缓冲区的数据
 *
 * 三、缓存区的四个核心属性
 * position <= limit <= capacity
 * capacity：容量，表示缓冲区最大存储数据的容量，一旦声明不能改变
 * limit：界限，表示缓冲区可以操作数据的大小（limit后边数据不能进行读写）
 * position: 位置：表示缓冲区中正在操作数据的位置
 *
 *  四、直接缓冲区与非直接缓冲区
 *  非直接缓冲区：通过allocate方法分配缓冲区，将缓冲区建立在jvm的内存中
 *  直接缓冲区：通过allocateDirect方法分配直接缓冲区，将缓冲区建立在物理内存中，可以提高效率
 */
@Slf4j
public class NioP2Buffer {

    /**
     * 缓冲区操作
     */
    public void  bufferOption(){
        String data = "abcde";
        //1.分配指定大小缓存区
        ByteBuffer buf = ByteBuffer.allocate(1024);
        log.info("初始化 capacity = {}, limit = {}, position = {}",
                buf.capacity(),
                buf.limit(),
                buf.position());

        //2.利用put存入数据到缓冲区
        buf.put(data.getBytes(StandardCharsets.UTF_8));
        log.info("数据存储后 capacity = {}, limit = {}, position = {}",
                buf.capacity(),
                buf.limit(),
                buf.position());

        //3.切换缓冲区模式(读数据模式)，flip
        buf.flip();
        log.info("（读取模式） capacity = {}, limit = {}, position = {}",
                buf.capacity(),
                buf.limit(),
                buf.position());

        //4.get读取数据
        byte[] bytes = new byte[buf.limit()];
        buf.get(bytes);
        String readResult = new String(bytes);
        log.info("数据读取结果：{}", readResult);

        //5.rewind重复读取数据
        buf.rewind();
        log.info("重复读取数据 capacity = {}, limit = {}, position = {}",
                buf.capacity(),
                buf.limit(),
                buf.position());

        //6.clean清除缓冲区,数据依然存储，数据处于被遗忘状态
        buf.clear();
        log.info("清除缓冲区 capacity = {}, limit = {}, position = {}",
                buf.capacity(),
                buf.limit(),
                buf.position());

        log.info("清除缓冲区，读取数据 = {}", (char)buf.get());
    }

    /**
     * 缓冲区操作
     */
    public void  bufferOptionChinese(){
        String data = "广东罗浮山";
        ByteBuffer buf = ByteBuffer.allocate(1024);
        //2.利用put存入数据到缓冲区
        buf.put(data.getBytes(StandardCharsets.UTF_8));
        //3、切换读取模式
        buf.flip();

        //4.mark标记位置
        byte[] tempBytes = new byte[buf.limit()];
        buf.get(tempBytes, 0, 3);
        log.info("数据读取结果：0 -> 3 {}", new String(tempBytes));
        buf.mark();
        log.info("mark capacity = {}, limit = {}, position = {}",
                buf.capacity(),
                buf.limit(),
                buf.position());

        //4.get读取数据
        byte[] bytes = new byte[buf.limit()];
        buf.get(bytes,3,12);
        String readResult = new String(bytes);
        log.info("数据读取结果：{}", readResult);
        log.info("（读取模式） capacity = {}, limit = {}, position = {}",
                buf.capacity(),
                buf.limit(),
                buf.position());

        //恢复到mark位置
        buf.reset();
        log.info("reset capacity = {}, limit = {}, position = {}",
                buf.capacity(),
                buf.limit(),
                buf.position());


        //是否還存在可以操作的數據
        if(buf.hasRemaining()){
            log.info("緩存區剩餘數據長度：{}字節", buf.remaining());
        }



    }


}

